# -*-coding: utf-8 -*-
"""
    @Theme   : 
    @Time    : 2024/7/16 9:54
    @Author  : YamFish
    @Url     : https://www.zhihu.com/people/yamfish
"""
import datetime
from typing import List, Tuple

from bson import ObjectId


class MongoUtil(object):
    def __init__(self, app, client):
        self.question = app.config['MONGO_QUESTION_COLLECTION']
        self.answer = app.config['MONGO_ANSWER_COLLECTION']
        self.user = app.config['MONGO_USER_COLLECTION']
        self.vote = app.config['MONGO_VOTE_COLLECTION']
        self.client = client
        self.client.set_handler(self.question)
        self.client.set_handler(self.user)
        self.client.set_handler(self.answer)
        self.client.set_handler(self.vote)

    def query_question(self, question_id_score_list: List[Tuple[bytes, int]]) -> (dict, int):
        id_score_dict = {}
        id_order_dict = {}
        object_id_list = []

        for index, question_id_score in enumerate(question_id_score_list):
            question_id = question_id_score[0].decode()
            score = int(question_id_score[1])
            id_score_dict[question_id] = score
            id_order_dict[question_id] = index
            object_id_list.append(ObjectId(question_id))

        question_iter_obj = self.client.aggregate(
            self.question,
            [
                {'$match': {'_id': {'$in': object_id_list}}},
                {'$lookup': {
                    'from': 'answer',
                    'localField': '_id',
                    'foreignField': 'question_id',
                    'as': 'answer_list'}}
            ])

        question_list = []
        for question in question_iter_obj:
            question_id = str(question['_id'])
            question_list.append(
                {'title': question['title'],
                 'detail': question['detail'],
                 'author': question['author'],
                 'timestamp': question['ask_time'].strftime('%Y-%m-%d %H:%M:%S'),
                 'vote_up': id_score_dict[question_id],
                 'answer_number': len(question['answer_list']),
                 'question_id': question_id
                 }
            )

        total_question = self.client.get_count(self.question, {})
        question_list = sorted(question_list, key=lambda x: id_order_dict[x['question_id']])
        return question_list, total_question

    def query_answer(self, question_id, answer_id_score_list: List[Tuple[bytes, int]]) -> dict:
        object_id_list = []
        id_score_dict = {}
        id_order_dict = {}
        for index, answer_id_score in enumerate(answer_id_score_list):
            answer_id = answer_id_score[0].decode()
            score = int(answer_id_score[1])
            id_score_dict[answer_id] = score
            id_order_dict[answer_id] = index
            object_id_list.append(ObjectId(answer_id))
        question = self.client.find_one(self.question, {'_id': ObjectId(question_id)})
        question_answer_dict = {
            'question_id': question_id,
            'question_title': question['title'],
            'question_detail': question['detail'].split('\n'),
            'question_author': question['author'],
            'answer_num': self.client.get_count(self.answer, {'question_id': ObjectId(question_id)})
        }
        answer_list = []
        for answer in self.client.find(self.answer, {'_id': {'$in': object_id_list}}):
            answer_id = str(answer['_id'])
            answer_list.append(
                {'answer_detail': answer['answer'].split('\n'),
                 'answer_author': answer['author'],
                 'answer_id': answer_id,
                 'answer_vote': id_score_dict[answer_id]})
        answer_list = sorted(answer_list, key=lambda x: id_order_dict[x['answer_id']])
        question_answer_dict['answer_list'] = answer_list
        return question_answer_dict

    def insert_answer(self, question_id, answer, author, now):
        data_to_insert = {
            'author': author,
            'question_id': ObjectId(question_id),
            'answer': answer,
            'answer_time': now,
        }
        doc_id = self.client.insert_one(self.answer, data_to_insert)
        return str(doc_id)

    def insert_question(self, title, detail, author, now):
        data_to_insert = {
            'title': title,
            'detail': detail,
            'author': author,
            'ask_time': now,
        }
        doc_id = self.client.insert_one(self.question, data_to_insert)
        return str(doc_id)

    def do_vote(self,  doc_type: str, doc_id: str, value: int, user: str, vote_time: datetime.datetime):
        data = {
            'doc_type': doc_type,
            'doc_id': doc_id,
            'value': value,
            'user': user,
            'vote_time': vote_time
        }
        self.client.insert_one(self.vote, data)

    def save_user_info(self, user, password_hash):
        user_info = {
            'user': user,
            'password_hash': password_hash,
            'avatar': '',
            'register_time': datetime.datetime.now()
        }
        user_id = self.client.insert_one(self.user, user_info)
        return str(user_id)

    def get_user_info(self, user):
        user_info = self.client.find_one(self.user, {'user': user})
        if not user_info:
            return {'success': False, 'reason': '找不到用户名！'}
        return {'success': True, 'user_info': user_info}

    def update_question(self, question_id, title, text):
        result = self.client.update_one(
            self.question,
            {'_id': ObjectId(question_id)},
            {'$set': {'title': title, 'detail': text}}
        )
        # toDO
        print(result)
        return True

    def update_answer(self, answer_id, text):
        result = self.client.update_one(
            self.answer,
            {'_id': ObjectId(answer_id)},
            {'$set': {'answer': text}}
        )
        # toDO
        print(result)
        return True

    def insert_vote(self, doc_type, doc_id, value, user, vote_time):
        data = {
            'doc_type': doc_type,
            'doc_id': ObjectId(doc_id),
            'value': value,
            'user': user,
            'vote_time': vote_time
        }
        self.client.insert_one(self.vote, data)
